﻿

using System.Drawing;
using OpenTK.Graphics;
using System.Drawing.Imaging;
using System;


namespace Rekx.Graphics
{
    /// <summary>
    /// This class represents a texture that can be bound to the context
    /// </summary>
    public class Texture : IDisposable
    {
        #region Member Variables

        int textureId;

        #endregion


        /// <summary>
        /// Id for the texture
        /// </summary>
        public int Id
        {
            get
            {
                return textureId;
            }
        }


        /// <summary>
        /// Creates a new texture from a filename
        /// </summary>
        /// <param name="filename">Path to the file. It has to be there, or crash.</param>
        public Texture(string filename)
        {

           

            GL.GenTextures(1, out textureId);
            Bind();

            // Get bitmap data from file
            LoadImageToOGL(filename);

            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);

            UnBind();


        }


        /// <summary>
        /// Loads an image into the currently bound texture
        /// </summary>
        /// <param name="filename">Path to the image used for texture</param>
        private static void LoadImageToOGL(string filename)
        {
            Bitmap bitmap = new Bitmap(filename);
            BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width,
                data.Height, 0, OpenTK.Graphics.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);

            bitmap.UnlockBits(data);
        }


        /// <summary>
        /// Binds the texture to the opengl context
        /// </summary>
        public void Bind()
        {
            GL.BindTexture(TextureTarget.Texture2D, textureId);
        }


        /// <summary>
        /// Unbinds the texture from the opengl context
        /// </summary>
        public void UnBind()
        {
            GL.BindTexture(TextureTarget.Texture2D, 0);
        }

        #region IDisposable Pattern
        // taken from msdn

        private bool disposed = false;

        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.

        /// <summary>
        /// Dispose the resources
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SupressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios.
        // If disposing equals true, the method has been called directly
        // or indirectly by a user's code. Managed and unmanaged resources
        // can be disposed.
        // If disposing equals false, the method has been called by the
        // runtime from inside the finalizer and you should not reference
        // other objects. Only unmanaged resources can be disposed.
        private void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if (disposing)
                {
                    // Dispose managed resources.
                    

                }

                // Call the appropriate methods to clean up
                // unmanaged resources here.
                // If disposing is false,
                // only the following code is executed.
                GL.DeleteTextures(1, ref textureId);

                // Note disposing has been done.
                disposed = true;

            }
        }

        #endregion
    }


}
